/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package servlets;

import connection.DBConnection;
import dto.Account;

import java.io.*;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import utilities.XMLUtilities;

/**
 * @author Tung An
 */
@WebServlet(name = "LoginServlet", urlPatterns = {"/LoginServlet"})
public class LoginServlet extends HttpServlet {

    /**
     * Processes requests for both HTTP
     * <code>GET</code> and
     * <code>POST</code> methods.
     *
     * @param request  servlet request
     * @param response servlet response
     * @throws javax.servlet.ServletException if a servlet-specific error occurs
     * @throws java.io.IOException            if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        String action = request.getParameter("action");
        try {
            if (action != null) {
                if (action.equalsIgnoreCase("checkusername")) {
                    boolean result = this.checkUsername(request.getParameter("username"));
                    out.write("<result>" + result + "</result>");
                } else if (action.equalsIgnoreCase("signup")) {
                    Account account = this.createAccountObj(request.getParameter("xml"));
                    account = this.createAccount(account);
                    out.write(XMLUtilities.marshallObj(account).toString());
                } else if (action.equalsIgnoreCase("login")) {
                    Account acc = this.checkLogin(request.getParameter("username"), request.getParameter("password"));
                    StringWriter xml = XMLUtilities.marshallObj(acc);
                    HttpSession session = request.getSession();
                    session.setAttribute("account", xml.toString());
                    out.write(xml.toString());
                } else if (action.equalsIgnoreCase("checklogged")) {
                    HttpSession session = request.getSession();
                    out.write(session.getAttribute("account").toString());
                } else if (action.equalsIgnoreCase("logout")) {
                    HttpSession session = request.getSession();
                    session.invalidate();
                }
            }

        } finally {
            out.close();
        }
    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">

    /**
     * Handles the HTTP
     * <code>GET</code> method.
     *
     * @param request  servlet request
     * @param response servlet response
     * @throws javax.servlet.ServletException if a servlet-specific error occurs
     * @throws java.io.IOException            if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP
     * <code>POST</code> method.
     *
     * @param request  servlet request
     * @param response servlet response
     * @throws javax.servlet.ServletException if a servlet-specific error occurs
     * @throws java.io.IOException            if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>

    private Account createAccount(Account account) {
        DBConnection con = new DBConnection("localhost", "root", "123456", "xml");
        String query = "INSERT INTO users (username, password, email, address, avatarURL, role) VALUES (?,?,?,?,?,?)";
        PreparedStatement st = con.prepareStatement(query);
        Integer result = 0;
        try {
            st.setString(1, account.getUsername());
            st.setString(2, account.getPassword());
            st.setString(3, account.getEmail());
            st.setString(4, account.getAddress());
            st.setString(5, account.getAvatarurl());
            st.setString(6, account.getRole());
            result = st.executeUpdate();
        } catch (SQLException ex) {
            Logger.getLogger(ProcessServlet.class.getName()).log(Level.SEVERE, null, ex);
        }
        con.close();

        if (result != 0) {
            return account;
        } else {
            return null;
        }
    }

    private Account createAccountObj(String xml) {
        if (xml.isEmpty()) {
            return null;
        }
        try {
            JAXBContext context = JAXBContext.newInstance(Account.class);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            InputStream stream = new ByteArrayInputStream(xml.getBytes());
            Account account = (Account) unmarshaller.unmarshal(stream);
            account.setRole("user");
            return account;
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return null;
    }

    private boolean checkUsername(String username) {
        try {
            DBConnection con = new DBConnection("localhost", "root", "123456", "xml");
            String query = "SELECT username FROM users WHERE username=?";
            PreparedStatement st = con.prepareStatement(query);
            st.setString(1, username.trim());
            ResultSet rs = st.executeQuery();
            if (rs.next()) {
                return false;
            } else {
                return true;
            }
        } catch (SQLException ex) {
            Logger.getLogger(LoginServlet.class.getName()).log(Level.SEVERE, null, ex);
        }
        return false;
    }

    private Account checkLogin(String username, String password) {
        try {
            DBConnection con = new DBConnection("localhost", "root", "123456", "xml");
            String query = "SELECT * FROM users WHERE username=? AND password=?";
            PreparedStatement st = con.prepareStatement(query);
            st.setString(1, username.trim());
            st.setString(2, password.trim());
            ResultSet rs = st.executeQuery();
            if (rs.next()) {
                Account account = new Account();
                account.setUserid(rs.getShort("userId"));
                account.setUsername(rs.getString("username"));
                account.setAddress(rs.getString("address"));
                account.setEmail(rs.getString("email"));
                String avatarURL = "";
                if (rs.getString("avatarURL") != null) {
                    avatarURL = rs.getString("avatarURL");
                }
                account.setAvatarurl(avatarURL);
                account.setRole(rs.getString("role"));
                return account;
            }
        } catch (SQLException ex) {
            Logger.getLogger(LoginServlet.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }
}
